// RMSWaveClientSocket.cpp: implementation of the CRMSWaveClientSocket class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Resource.h"

#include "../RMSLib/AudioOut/CAudioOut.h"
#include "../RMSLib/utility.h"
#include "RMSWaveClientSocket.h"

#include "../Common/CTags.h"

#include "Lib/Network.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define SETAUDIOSTATUS(a) SetAudioStatus(a)

#define _USE_FLIP_


#if defined(_USE_FLIP_) && defined(USE_OLD_SOCKET)
#	undef _USE_FLIP_
#endif

#include "../Common/sfec.h"

//#define mydebug
#ifdef mydebug
CMyDebug md("debug_vc10.log", false);
#endif

CWaveData::CWaveData()
{
	m_bFull = false;
	m_nSize = 0;
	m_nActiveBuffer = 0;
	m_dwBufLen = initial_buf_size;
	m_pWaveData = new BYTE[m_dwBufLen];
}

CWaveData::~CWaveData()
{
	delete[] m_pWaveData;
}
 
bool CWaveData::IsFull() const
{
	Lock lock(this);
	return m_bFull;
}

void CWaveData::ClearPacket()
{
	Lock lock(this);
	m_bFull = false;
}

long CWaveData::DecodePacket(CAudioDecoder *pDecoder, BYTE *pDst)
{
	Lock lock(this);
	return pDecoder->Decode(m_pWaveData, pDst);
}

void CWaveData::SetPacket(BYTE bPacketNum, DWORD dwWaveSize, BYTE* pData, DWORD dwWaveSizeToCopy)
{
	Lock lock(this);

	if(!m_pWaveData)
	{
		m_dwBufLen = initial_buf_size;
		m_pWaveData = new BYTE[m_dwBufLen];
	}

	if(dwWaveSizeToCopy > m_dwBufLen)
	{
		dwWaveSizeToCopy = m_dwBufLen;
	}
	if(pData)
	{
		::CopyMemory(m_pWaveData, pData, dwWaveSizeToCopy);
	}

	m_nSize = dwWaveSize;
	m_nActiveBuffer = bPacketNum;
	m_bFull = true;
}


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CRMSWaveClientSocket::CRMSWaveClientSocket():
	m_threadState(STATE_STOP),
	m_bActive(false),
//	m_bSync(false),
	m_UDPsocket(0),
	m_bSessionStarted(false)
{
#ifdef WIN32
	m_hStateEvents[0] = ::CreateEvent(NULL, FALSE, FALSE, NULL);
#endif //def WIN32

    pFEC = NULL;//new CSimpleFEC(50, 4, (unsigned int)TAG_RMSSOUND_v01, (unsigned int) TAG_RMSFEC_PSHUF1); // first two parameters are not important for decoding;
    pCallBack = NULL;

    prebuf = 0;
	m_pData = 0;
	m_flip = 0;
	m_pData2[0] = m_pData2[1] = 0;
}

CRMSWaveClientSocket::~CRMSWaveClientSocket()
{
	Terminate();

    if (pFEC!=NULL) delete pFEC;

	delete m_pData;
	delete m_pData2[0];
	delete m_pData2[1];
}

void CRMSWaveClientSocket::OnError(int err/* = 0*/)
{
#ifdef WIN32
	String str;
	if(err == 0)
	{
		err = WSAGetLastError();
	}
	switch(err)
	{
		case WSANOTINITIALISED: str = " A successful WSAStartup must occur before using this function.  "; break;
		case WSAENETDOWN: str = "  The network subsystem has failed.  "; break;
		case WSAEAFNOSUPPORT: str = "The specified address family is not supported."; break;
		case WSAEMFILE: str = "No more socket descriptors are available."; break;
		case WSAENOBUFS: str = "No buffer space is available. The socket cannot be created."; break;
		case WSAEPROTONOSUPPORT: str = "The specified protocol is not supported."; break;
		case WSAEPROTOTYPE: str = "The specified protocol is the wrong type for this socket."; break;
		case WSAENOTCONN: str = "Connection has been reset when SO_KEEPALIVE is set."; break;
		case WSAENOPROTOOPT: str = "The option is unknown or unsupported for the specified provider or socket (see SO_GROUP_PRIORITY limitations)."; break;
		case WSAESOCKTNOSUPPORT: str = "The specified socket type is not supported in this address family."; break;
		case WSAEFAULT : str = " The buf or from parameters are not part of the user address space, or the fromlen parameter is too small to accommodate the peer address.  "; break;
		case WSAEINTR : str = " The (blocking) call was canceled through WSACancelBlockingCall.  "; break;
		case WSAEINPROGRESS: str = "  A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.  "; break;
		case WSAEINVAL : str = " The socket has not been bound with bind, or an unknown flag was specified, or MSG_OOB was specified for a socket with SO_OOBINLINE enabled, or (for byte stream-style sockets only) len was zero or negative.  "; break;
		case WSAEISCONN : str = " The socket is connected. This function is not permitted with a connected socket, whether the socket is connection-oriented or connectionless.  "; break;
		case WSAENETRESET : str = " The connection has been broken due to the keep-alive activity detecting a failure while the operation was in progress.  "; break;
		case WSAENOTSOCK : str = " The descriptor is not a socket.  "; break;
		case WSAEOPNOTSUPP : str = " MSG_OOB was specified, but the socket is not stream-style such as type SOCK_STREAM, out-of-band data is not supported in the communication domain associated with this socket, or the socket is unidirectional and supports only send operations.  "; break;
		case WSAESHUTDOWN : str = " The socket has been shut down; it is not possible to recvfrom on a socket after shutdown has been invoked with how set to SD_RECEIVE or SD_BOTH.  "; break;
		case WSAEWOULDBLOCK : str = " The socket is marked as nonblocking and the recvfrom operation would block.  "; break;
		case WSAEMSGSIZE : str = " The message was too large to fit into the specified buffer and was truncated.  "; break;
		case WSAETIMEDOUT : str = " The connection has been dropped, because of a network failure or because the system on the other end went down without notice.  "; break;
		case WSAECONNRESET : str = " The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket as it is no longer usable. On a UDP datagram socket this error would indicate that a previous send operation resulted in an ICMP Port Unreachable message. "; break;
		case WSAEADDRINUSE : str = "A process on the machine is already bound to the same fully-qualified address and the socket has not been marked to allow address re-use with SO_REUSEADDR."; break;
		case WSAEADDRNOTAVAIL : str = "The specified address is not a valid address for this machine"; break;
		default:
			str = "unknown error";
	};
#ifdef	_DEBUG
	errOut(__FILE__, __LINE__, _T("OnError(socket error %i - %s"), err, str.c_str());
#endif
#endif //def WIN32
}

BOOL CRMSWaveClientSocket::StartWaveSession(ClientInterface* pClient , const char *szIP, int nPort)
#ifdef USE_OLD_SOCKET
{
	STATE state = STATE_RUN;
	bool bBind = false;
	int i;

	setClient(pClient);


	if(m_bSessionStarted)
	{
		StopWaveSession();
		state = STATE_RESTART;
	}

	mesOut(__FILE__, __LINE__, _T("StartWaveSession(IP=\"%s\", nPort=%i)"), szIP, nPort);

    m_LastStored=0;
	m_eventSync.ResetEvent();
    prebuf = 0;

	::memset(&m_saServer, 0, sizeof(m_saServer));
	m_saServer.sin_family = PF_INET;
	m_saServer.sin_addr.s_addr = inet_addr(szIP);
	m_saServer.sin_port = htons(nPort);

	m_UDPsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if(m_UDPsocket == INVALID_SOCKET)
	{
		OnError();
		CloseSession();
		return FALSE;
	}

#ifndef WIN32
    (void)fcntl(m_UDPsocket, F_SETFD, 1);
#else //ndef WIN32
	{
		//Fixes Bug in MFC Socket Impl
		LINGER linger = { 1,0 };
		setsockopt(m_UDPsocket, SOL_SOCKET, SO_LINGER, (LPCTSTR)&linger, sizeof(linger));
		BOOL bReuse = 1;
//		setsockopt(m_UDPsocket, SOL_SOCKET, SO_REUSEADDR,(LPCTSTR)&bReuse,sizeof(BOOL));
	}
#endif //ndef WIN32

	//-------------------------------------------------------
	if(m_pData == 0)
	{
		m_pData = new BYTE[PACKET_SIZE*100];
	}

	//-------------------------------------------------------
	// bind socket

	::memset(&m_saClient, 0, sizeof(m_saClient)); 
	m_saClient.sin_family = PF_INET;
	m_saClient.sin_port = htons(REGISTRY_LoadInt(KEY_SERVER_PORT, 777) + 200);// start with +200
	m_saClient.sin_addr.s_addr = INADDR_ANY;

	// find and bin local port to bind to
	for(i = 0; i < 100; i++) 
	{
		//int option=1;setsockopt (m_udpSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&option, sizeof (option));
		if(bind(m_UDPsocket, (struct sockaddr*)&m_saClient, sizeof(sockaddr_in)) != INVALID_SOCKET)
		{
			mesOut(__FILE__, __LINE__, _T("StartWaveSession(), socket is bound "
				   "successfully, m_saClient.sin_port=%i"), m_saClient.sin_port);
			bBind = true;
			break;
		}
		else
		{
			m_saClient.sin_port = htons(ntohs(m_saClient.sin_port) + 1);
		}
	}

	if(!bBind)
	{
		mesOut(__FILE__, __LINE__, _T("StartWaveSession(), Unable to bind socket"));
		CloseSession();
		return FALSE;
	}

	m_bSessionStarted = true;
	SetState(state);

	return TRUE;
}
#else //def USE_OLD_SOCKET
{
	setClient(pClient);

	STATE state = STATE_RUN;
	if(m_bSessionStarted)
	{
		StopWaveSession();
		state = STATE_RESTART;
	}

	mesOut(__FILE__, __LINE__, _T("StartWaveSession(IP=%s, nPort=%i)"), szIP, nPort);

	m_eventSync.ResetEvent();

	::memset(&m_saServer, 0, sizeof(m_saServer));
	m_saServer.sin_family = PF_INET;
	m_saServer.sin_addr.s_addr = inet_addr(szIP);
	m_saServer.sin_port = htons(nPort);

	if(!initSocket(&m_UDPsocket, nPort))
	{
		errOut(__FILE__, __LINE__, _T("StartWaveSession(), Unable to create udp socket"));
		CloseSession();
		return FALSE;
	}

	//-------------------------------------------------------
	if(0 == m_pData)
	{
		m_pData = new BYTE[PACKET_SIZE*100];
	}

	if(0 == m_pData2[0])
	{
		m_pData2[0] = new BYTE[PACKET_SIZE*100];
		::memset(m_pData2[0], 0, PACKET_SIZE*100);
	}

	if(0 == m_pData2[1])
	{
		m_pData2[1] = new BYTE[PACKET_SIZE*100];
		::memset(m_pData2[1], 0, PACKET_SIZE*100);
	}

	m_flip = 0;

	setNonDelayMode(&m_UDPsocket);
	m_bSessionStarted = true;
	SetState(state);

	return TRUE;
}
#endif //def USE_OLD_SOCKET

BOOL CRMSWaveClientSocket::StopWaveSession()
{
	mesOut(__FILE__, __LINE__, _T("StopWaveSession(), state=%i"), GetState());

	m_bSync = 0;
	CloseSession();
	m_eventSync.ResetEvent();
	m_bSessionStarted = false;

	return TRUE;
}

//CSimpleFEC fec(50, 4, (unsigned int)TAG_RMSSOUND_v01, (unsigned int) TAG_RMSFEC_PSHUF1); // first two parameters not important for decoding


bool CRMSWaveClientSocket::ParseTags(DWORD& dwTag, BYTE*& pSrc, int Len)
{
	int szAudio = 0;

#if defined(_PACKET_LOSS_)
    int bufdelay = gBufSize/20;
#endif
	switch(dwTag)
	{
		case TAG_RMSSOUND_v01: case TAG_RMSFEC_PSHUF1:
                                 
                                 if (Len<sizeof(BYTE)+sizeof(int)) return false;
#ifdef mydebug
                                 static char info[192];
                                 if(/*(rand()>>8)%64==7*/0)
                                 {
                                   static int Killer=0;
                                   Killer++;
                                   string s="A";
                                   if(dwTag==TAG_RMSFEC_PSHUF1) s="P";
                                   sprintf(info, "nReceived(%d), nReceivedP(%d), nRepaired(%d), nNotRepaired(%d), nLost(%d), Killer(%d)/%s",
                                     pFEC->nReceived, pFEC->nReceivedP, pFEC->nRepaired, pFEC->nNotRepaired, pFEC->nLost, Killer, s.c_str());
                                   md.printstr(info);
                                   return false;
                                 }
                                 sprintf(info, "// nReceived(%d), nReceivedP(%d), nRepaired(%d), nNotRepaired(%d), nLost(%d), nTooLate(%d)",
                                   pFEC->nReceived, pFEC->nReceivedP, pFEC->nRepaired, pFEC->nNotRepaired, pFEC->nLost, pFEC->nTooLate);
                                 md.printstr(info);
#endif
                                 //md.printsome("pck("+md.inttostr(dwTag)+")", pSrc, 100, Len);

            if(dwTag==TAG_RMSSOUND_v01) pFEC->AddNormalPacket(pSrc, Len); else
            if(dwTag==TAG_RMSFEC_PSHUF1) pFEC->AddParityPacket(pSrc, Len);

if(gBufSize==0)gBufSize=250;


            unsigned char buf[33];
            unsigned char no;
            
            // if(!pFEC->GetSample(buf, &no)) return false;
///            int delay = gBufSize*4/5 /20;
///            int bufdelay = gBufSize*1/5 /20;
#if !defined(_PACKET_LOSS_)
            int bufdelay = gBufSize/20;
#endif
            if(!pFEC->GetSampleDelayed(buf, &no, -1/*delay*/)) return false;

            //            |      bufdelay      |    delay   |
            //   past --> | anti-jitter buffer | fec buffer | --> future
            //            | ****************** | **** * **  |

                                  
			m_criticalAction.Lock();

            m_byPacketNumber = no;

            if (prebuf==0)
              m_byPacketNumberStart = m_byPacketNumber;
            else
            {
#ifdef mydebug
md.printstr("prebuf = "+md.inttostr(prebuf));
#endif
              if (prebuf>=gBufSize)
              {
                int st = (m_byPacketNumber + PACKET_COUNT - bufdelay) % PACKET_COUNT;
#ifdef mydebug
md.printstr("start: "+md.inttostr(m_byPacketNumberStart)+" -> "+md.inttostr(st));
#endif
                m_byPacketNumberStart = st;
              }
            }

			m_criticalAction.Unlock();
            do
			{
				m_criticalAction.Lock();
           	    m_Audio[m_byPacketNumber].SetPacket(m_byPacketNumber, WAVE_SIZE*2, buf, 33);
				m_criticalAction.Unlock();

				if ( (gBufSize!=0) && (prebuf<gBufSize) )
                  prebuf += 20; // assume 1 sample = 0.02 sec
                else
                  m_eventSync.SetEvent();

				m_criticalAction.Lock();
				if(m_bSync == 0)
				{
//					if(m_byPacketNumber == PACKET_SYNC)
                    if( ((prebuf>=gBufSize)&&(gBufSize!=0)) || ((gBufSize==0)&&(m_byPacketNumber == PACKET_SYNC)))
					{
						m_bSync = 1;
						SETAUDIOSTATUS(AUDIO_STATUS_PLAY);
					}
					else
					{
						SETAUDIOSTATUS(AUDIO_STATUS_BUFFERING);
						m_bSync = 0;
					}
				}
                m_LastStored=m_byPacketNumber;
				m_criticalAction.Unlock();
//			} while(pFEC->GetSample(buf, &m_byPacketNumber));
    		} while(pFEC->GetSampleDelayed(buf, &m_byPacketNumber, -1/*delay*/));
  // notify caller:

  if(gDisplayStats>0 && pCallBack)
    if(Can.Start("DisplayStats", gDisplayStats)) pCallBack->Execute(pFEC);

  if(gCallerWindowHandle!=0)
  {
    if(Can.Start("FECstats", gNotifyPeriod))
    {
      WPARAM x1; // nAll (10) | nActual (10) | nLate (10)
      LPARAM x2; // ClientID (6) | nDrop (10) | nParityReceived (10)

// what we got: pFEC->nReceived, pFEC->nReceivedP, pFEC->nRepaired, pFEC->nNotRepaired, pFEC->nLost
      int
        nAll = pFEC->nReceived + pFEC->nLost,
        nActual = pFEC->nReceived,
        nLate = pFEC->nTooLate,
        ClientID = gNotifyClientID,
        nDrop = pFEC->nLost - pFEC->nRepaired;

      x1 = (Saturate(nAll, 0, 1023)<<20) | (Saturate(nActual, 0, 1023)<<10) | Saturate(nLate, 0, 1023);
      x2 = (Saturate(ClientID, 0, 63)<<20) | (Saturate(nDrop, 0, 1023)<<10) | Saturate(pFEC->nReceivedP, 0, 1023);

//md.printstr(md.inttostr(nAll)+ "|" +md.inttostr(nActual)+ "|" +md.inttostr(nDrop)+ "  (" +md.inttostr(pFEC->nReceivedP)+")");

      PostMessage(gCallerWindowHandle, gNotifyMsgID, x1, x2 );

      if(gDisplayStats==-1 && pCallBack) pCallBack->Execute(pFEC);

      pFEC->ClearStats();
    }
  } else
  if(gDisplayStats==-1 && pCallBack)
    if(Can.Start("DisplayStats", 3)) pCallBack->Execute(pFEC);


			break;
		default:
                      {
			// This format of audio is not supported
                                 pFEC->AddOtherPacket(pSrc, Len);
			return false;
                      }
	}
	return true;
}

bool CRMSWaveClientSocket::MakeThreadStep(int& nLen, BYTE*& pSrc, DWORD& dwTag)
{
	int szAudio = 0;
	int bRecieved = 0;
	nLen = sizeof(SOCKADDR_IN);

#ifdef _USE_FLIP_
	pSrc = m_pData2[m_flip];
#else //def _USE_FLIP_
	pSrc = m_pData;
#endif //def _USE_FLIP_

#ifdef USE_OLD_SOCKET
	bRecieved = MyRecieveData(&m_UDPsocket, (char*)pSrc, PACKET_SIZE*100, 0,
							  (LPSOCKADDR)&m_saServer, &nLen);
#else //def USE_OLD_SOCKET
    nLen=PACKET_SIZE*100;
	bRecieved = recievePacket(&m_UDPsocket, pSrc, nLen);
#endif //def USE_OLD_SOCKET

	if(bRecieved>=sizeof(DWORD))
	{
#if defined(_USE_FLIP_)
		m_flip ^= 1;
		pSrc = m_pData2[m_flip^1];
#endif // _USE_FLIP_
		dwTag = *((DWORD*)pSrc); pSrc += sizeof(DWORD);

        return ParseTags(dwTag, pSrc,bRecieved);

	}

	return false;
}

DWORD CRMSWaveClientSocket::ThreadFunc()
{
	mesOut(__FILE__, __LINE__, _T("enter ThreadFunc()"));

	int nLen, nPort;
	DWORD dwTag;
	BYTE* pSrc;

restart:
	m_bActive = true;
//	SetThreadPriority(m_hThread, THREAD_PRIORITY_NORMAL);
           SetThreadPriority(m_hThread, THREAD_PRIORITY_HIGHEST);
           

	long sTime = 0;
	int samlpes = 0;

	// Send udp port 
	dwTag = TAG_SOUNDUDPPORT;
	nPort = ntohs(m_saClient.sin_port);
	nLen = sizeof(DWORD) + sizeof(int);
	pSrc = m_pData;
	memcpy(pSrc, &dwTag, sizeof(DWORD));
	pSrc += sizeof(DWORD);
	memcpy(pSrc, &nPort, sizeof(int));
	if(sendto(m_UDPsocket, (char*)m_pData, nLen, 0, (LPSOCKADDR)&m_saServer, sizeof(sockaddr_in)) == SOCKET_ERROR)
	{
		SETAUDIOSTATUS(AUDIO_STATUS_NONE);
		OnError();
		goto exit;
	}
	
	SETAUDIOSTATUS(AUDIO_STATUS_BUFFERING);
	Sleep(10);
	while(1)
	{
                      int state=GetState();
		switch(state)
		{
			case STATE_RESTART:
				SetState(STATE_RUN);
				goto restart;

			case STATE_RUN:
				MakeThreadStep(nLen, pSrc, dwTag);
				break;

			case STATE_STOP:
				WaitForStateChange(STATE_STOP);
				break;

			case STATE_EXIT:
				goto exit;
		}

//		Sleep(1);
	}
	SETAUDIOSTATUS(AUDIO_STATUS_NONE);

exit:
	CloseSession();
	StopWaveSession();
	m_bActive = false;
	mesOut(__FILE__, __LINE__, _T("exit ThreadFunc()"));
	return TRUE;
}

DWORD CRMSWaveClientSocket::OnTerminate()
{
	mesOut(__FILE__, __LINE__, _T("OnTerminate(), state=%i"), GetState());
	SetState(STATE_EXIT);
	return DEFAULT_TERMINATION_TIMEOUT;
}

void CRMSWaveClientSocket::OnCriticalTerminate()
{
	mesOut(__FILE__, __LINE__, _T("OnCriticalTerminate(), m_bTerminated=%i"), m_bTerminated);
	CloseSession();
}

void CRMSWaveClientSocket::CloseSession()
{
	closeSocket(&m_UDPsocket);
}

const CRMSWaveClientSocket::STATE& CRMSWaveClientSocket::GetState()
{
	Lock lock(this);
	return m_threadState;
}

bool CRMSWaveClientSocket::SetState(const CRMSWaveClientSocket::STATE& rState)
{
	Lock lock(this);

	m_threadState = rState;

	switch(rState)
	{
		case STATE_RUN:
			if(!m_bActive)
			{
				Execute();
			}
			else
			{
				::SetEvent(m_hStateEvents[0]);
			}
			break;

		case STATE_RESTART:
			::SetEvent(m_hStateEvents[0]);
			break;
	}
	return true;
}

void CRMSWaveClientSocket::WaitForStateChange(const CRMSWaveClientSocket::STATE& rPrevState)
{
	while(GetState() == rPrevState)
	{
		Sleep(10);
	}
}


#ifdef USE_OLD_SOCKET

bool CRMSWaveClientSocket::MyRecieveData(
										 STREAMBOX_SOCKET* s,
										 char FAR* buf,
										 int len,
										 int flags,
										 struct sockaddr FAR *from,
										 int FAR *fromlen
										)
{
	int nTryCount = 0;
	int nMaxTry = 30;
repeat:
//	int res = recv(*s, buf, len, flags);
//	if(res < 0)
	int res = recvfrom(*s, buf, len, flags, (LPSOCKADDR)from, fromlen);

	if(res == SOCKET_ERROR)
	{
		int err = WSAGetLastError();
		if(WSAEINTR != err)
		{
			OnError(err);
			return false;
		}
		else
		{
			// ignore error and try to retrieve data again
			if(++nTryCount < nMaxTry)
			{
				TRACE0("\nrepeat recive audio data\n");
				goto repeat;
			}
			return false;
		}
	}
	m_currecv += res;
	return true;
}

#else //def USE_OLD_SOCKET

int CRMSWaveClientSocket::initSocket(STREAMBOX_SOCKET* pSock/*, const char* szLocalIP*/, int nTCPPort/* = 777*/)
{
	SOCKADDR_IN addrDecoder;

    if(pFEC!=NULL) delete pFEC;
    pFEC = new CSimpleFEC(50, 4, (unsigned int)TAG_RMSSOUND_v01, (unsigned int) TAG_RMSFEC_PSHUF1); // first two parameters are not important for decoding

	if(!pSock)
		return 0;

	*pSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if(*pSock == INVALID_SOCKET)
	{
		OnError();
		return 0;
	}

#ifndef WIN32
    (void) fcntl( *pSock, F_SETFD, 1 );
#else //ndef WIN32
	//Fixes Bug in MFC Socket Impl
	LINGER linger = { 1,0 };
	setsockopt(*pSock, SOL_SOCKET, SO_LINGER, (LPCTSTR)&linger, sizeof(linger));
	BOOL bReuse = 1;
//	setsockopt(*pSock, SOL_SOCKET, SO_REUSEADDR,(LPCTSTR)&bReuse,sizeof(BOOL));
	// should not use same port as TCP !!!
#endif //ndef WIN32

	//--------------------------------------------------
	// bind socket 
	int Bind = 0;
	::memset(&addrDecoder, 0, sizeof(addrDecoder));
	addrDecoder.sin_family = AF_INET;
	addrDecoder.sin_addr.s_addr = INADDR_ANY;//inet_addr(szLocalIP);
	addrDecoder.sin_port = htons(nTCPPort + 200);// start with +200
	for(int i = 0; i < 100; i++) 
	{
		if(bind(*pSock, (LPSOCKADDR)&addrDecoder, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
		{
			addrDecoder.sin_port = htons(ntohs(addrDecoder.sin_port) + 1);
		}
		else
		{
			Bind = 1;
			break;
		}
	}

	if(!Bind)
	{
		OnError();
		return 0;
	}
/*
	int err;
	int optlen = sizeof(int);
	int old_bufsize = 64000000;
    err = setsockopt(*pSock, SOL_SOCKET, SO_RCVBUF, (char*)&old_bufsize, optlen);
	old_bufsize=0;
    err = getsockopt(*pSock, SOL_SOCKET, SO_RCVBUF, (char*)&old_bufsize, &optlen);
*/
	int err;
	int optlen = sizeof(int);
	int old_bufsize = 0;
    err = setsockopt(*pSock, SOL_SOCKET, SO_RCVBUF, (char*)&old_bufsize, optlen);
    err = getsockopt(*pSock, SOL_SOCKET, SO_RCVBUF, (char*)&old_bufsize, &optlen);
	return 1;
}

int CRMSWaveClientSocket::recievePacket(STREAMBOX_SOCKET *pSock, void *buf, int nBufSize)
{
	int nLen=0;

/*
	int err;
	int timeout;
	int len = sizeof(timeout);
	timeout = 1;
    err = setsockopt(*pSock, SOL_SOCKET, SO_RCVTIMEO, (char* FAR)&timeout, len);
	timeout = 0;
    err = getsockopt(*pSock, SOL_SOCKET, SO_RCVTIMEO, (char* FAR)&timeout, &len);
*/

	//int d=timeGetTime();
	//nLen=recv(Transport_UPD_Socket,(char*)data, 4096,0);

    FD_SET fdread;
//    timeval t = { 0, 1 };     // wait up to 10ms --- WRONG(!) Actually it's 0.001 ms which is 10000 (ten thousand) times less!
    timeval t = { 0, 100000 };  // we'd better wait 0.1sec which works
    FD_ZERO(&fdread);
    FD_SET(*pSock, &fdread);

	nLen = select(0, &fdread, NULL, NULL, &t);
	if(nLen == SOCKET_ERROR)
	{
		OnError();
		nLen = 0;
	}
	else if(nLen != 0)
	{
		nLen = recv(*pSock,(char*)buf, nBufSize,0);
		if(nLen == SOCKET_ERROR)
		{
			OnError();
			nLen = 0;
		}
#ifdef mydebug
//           md.printsome("pck("+md.inttostr(nLen)+")", (unsigned char*)buf, 30, nLen);
#endif
	}


	/*
	// check if it is audio packet

	BYTE* Data=(BYTE*) data;
	if (nLen && (Data[0]==0xA7)) {
		LastAudioTimeReceived=*(DWORD*)(Data+nLen-4);
	}
	*/

	return nLen;
}

int CRMSWaveClientSocket::setNonDelayMode(STREAMBOX_SOCKET *pSock)
{
	if(!pSock)
		return 0;

	unsigned long flags = 0;

#ifndef WIN32
	unsigned long res = 0;

    flags = fcntl( *pSock, F_GETFL, 0 );
    if ( flags == -1 )
	{
		TRACE1("fcntl F_GETFL -%m\n", flags);
		return 0;
	}
	res = fcntl( *pSock, F_SETFL, flags | O_NDELAY );
    if ( res < 0 )
	{
		TRACE1("fcntl O_NDELAY - %m\n",  res);
		return 0;
	}
#else
	int res;

	flags = 1;
	res = ioctlsocket(*pSock, FIONBIO, &flags);
	if(res == SOCKET_ERROR)
	{
		OnError();
		return 0;
	}

	int timeout = 1;
	int len = sizeof(timeout);
	res = setsockopt(*pSock, SOL_SOCKET, SO_RCVTIMEO, (char* FAR)&timeout, len);
	if(res == SOCKET_ERROR)
	{
		OnError();
		return 0;
	}
#endif

	return 1;
}

#endif //def USE_OLD_SOCKET

int CRMSWaveClientSocket::closeSocket(STREAMBOX_SOCKET* pSock)
{
	if(!pSock)
		return 0;

#ifdef WIN32
	shutdown(*pSock, SD_BOTH);
	closesocket(*pSock);
#else //def WIN32
	(void)close(*pSock);
#endif //def WIN32
	*pSock = 0;

	return 1;
}
